/***********************************************************************************************************************
* File Name    : r_cg_can.c
* Version      :
* Device(s)    : R5F10PPJ
* Tool-Chain   : CCRL
* Description  : This file implements device driver for CAN module.
* Creation Date: 2017/5/9
***********************************************************************************************************************/

/***********************************************************************************************************************
Includes
***********************************************************************************************************************/
#include "r_cg_macrodriver.h"
#include "r_cg_can.h"

/***********************************************************************************************************************
Pragma directive
***********************************************************************************************************************/
/* Start user code for pragma. Do not edit comment generated here */
/* End user code. Do not edit comment generated here */

/***********************************************************************************************************************
Global variables and functions
***********************************************************************************************************************/
/* Start user code for global. Do not edit comment generated here */
/* End user code. Do not edit comment generated here */

/***********************************************************************************************************************
* Function Name: R_CAN0_Create
* Description  : This function initializes the CAN0 module.
* Arguments    : None
* Return Value : None
***********************************************************************************************************************/
void R_CAN0_Create(void)
{
   //enable CAN module
   PER2_bit.no0 = 1;

   //start supply CAN clock
   CANCKSEL = 0x01;

   //wait CAN RAM initialization
   while(GSTS & _08_CAN_GSTS_GRAMINIT_1);

   //global reset mode
   GCTRL = _0000_CAN_GCTRL_THLEIE_0 | _0000_CAN_GCTRL_MEIE_0 | _0000_CAN_GCTRL_DEIE_0 | _0000_CAN_GCTRL_GSLPR_0 | _0001_CAN_GCTRL_GMDC_1;

   while(GSTS != _01_CAN_GSTS_GRSTSTS_1);

   //channel reset mode
   C0CTRL = _0000_CAN_C0CTRL_ALIE_0 | _0000_CAN_C0CTRL_BLIE_0 | _0000_CAN_C0CTRL_OLIE_0 | _0000_CAN_C0CTRL_BORIE_0 | _0000_CAN_C0CTRL_BOEIE_0 |
            _0000_CAN_C0CTRL_EPIE_0 | _0000_CAN_C0CTRL_EWIE_0 | _0000_CAN_C0CTRL_BEIE_0 | _0000_CAN_C0CTRL_CSLPR_0 | _0001_CAN_C0CTRL_CHMDC_1;

   while(C0STSL != _0001_CAN_C0STSL_CRSTSTS_1);

   //set clock (250kbps)  fcan=16MHz, 16Tq, 4 division
   GCFGL = _0000_CAN_GCFGL_TSSS_0 | _0000_CAN_GCFGL_TSP_0 | _0000_CAN_GCFGL_DCS_0 | _0000_CAN_GCFGL_MME_0 | _0000_CAN_GCFGL_DRE_0 |
           _0000_CAN_GCFGL_DCE_0 | _0000_CAN_GCFGL_TPRI_0;
   C0CFGH = _0000_CAN_C0CFGH_SJW_0 | _0030_CAN_C0CFGH_TSEG2_3 | _000A_CAN_C0CFGH_TSEG1_10;  // 1+4+11=16Tq
   C0CFGL = _0003_CAN_C0CFGL_BRP_3;

   //set receive rules (16 receive rules)
   GAFLCFGL = 16;
   GRWCR = _0001_CAN_GRWCR_RPAGE_1;

   //set buffer (16 receive buffers)
   RMNB = 16;

   //set interrupt

   //global operating mode
   GCTRL = _0000_CAN_GCTRL_THLEIE_0 | _0000_CAN_GCTRL_MEIE_0 | _0000_CAN_GCTRL_DEIE_0 | _0000_CAN_GCTRL_GSLPR_0 | _0000_CAN_GCTRL_GMDC_0;

   while(GSTS & (_08_CAN_GSTS_GRAMINIT_1 | _04_CAN_GSTS_GSLPSTS_1 | _02_CAN_GSTS_GHLTSTS_1 | _01_CAN_GSTS_GRSTSTS_1));

   //channel communication mode
   C0CTRL = _0000_CAN_C0CTRL_ALIE_0 | _0000_CAN_C0CTRL_BLIE_0 | _0000_CAN_C0CTRL_OLIE_0 | _0000_CAN_C0CTRL_BORIE_0 | _0000_CAN_C0CTRL_BOEIE_0 |
            _0000_CAN_C0CTRL_EPIE_0 | _0000_CAN_C0CTRL_EWIE_0 | _0000_CAN_C0CTRL_BEIE_0 | _0000_CAN_C0CTRL_CSLPR_0 | _0000_CAN_C0CTRL_CHMDC_0;

   while(C0STSL != _0080_CAN_C0STSL_COMSTS_1);

   C0ERFLL = 0;
}

/***********************************************************************************************************************
* Function Name: R_CAN0_Is_Received
* Description  : This function check if received CAN packet.
* Arguments    : buffer_num -
*                    CAN receive buffer number
* Return Value : result -
*                    1 - received; 0 - not received
***********************************************************************************************************************/
uint8_t R_CAN0_Is_Received(uint8_t buffer_num)
{
   if(RMND0 & (1 << buffer_num))
   {
      RMND0 &= ~(1 << buffer_num);
      return 1;
   }
   else
   {
      return 0;
   }
}

/***********************************************************************************************************************
* Function Name: R_CAN0_Read
* Description  : This function receives CAN0 data.
* Arguments    : buffer_num -
*                    CAN receive buffer number
*                rx_buf -
*                    receive buffer pointer
* Return Value : length -
*                    received data size
***********************************************************************************************************************/
uint8_t R_CAN0_Read(uint8_t buffer_num, uint16_t * id_hi, uint16_t * id_lo, uint8_t * rx_buf)
{
   uint16_t index, length;

   *id_hi = *(&RMIDH0 + buffer_num * 0x08);
   *id_lo = *(&RMIDL0 + buffer_num * 0x08);

   index = *(&RMPTR0 + buffer_num * 0x08);               //*0x10 for byte, *0x08 for word
   length = (*(&RMPTR0 + buffer_num * 0x10 / 2)) >> 12;  //*0x10 for byte, *0x08 for word

   for(index = 0; index < length; index++)
   {
      *(rx_buf++) = *(&RMDF00L + buffer_num * 0x10 + index);
   }

   return length;
}

/***********************************************************************************************************************
* Function Name: R_CAN0_Is_Transmitted
* Description  : This function check if ready for transmit CAN packet.
* Arguments    : buffer_num -
*                    CAN transmit buffer number
* Return Value : result -
*                    1 - ready; 0 - not ready
***********************************************************************************************************************/
uint8_t R_CAN0_Is_Transmitted(uint8_t buffer_num)
{
   uint16_t status;

   status = *(&TMSTS0 + buffer_num);

   if(status & (_0008_CAN_TMSTS_TMTRM_1 | _0001_CAN_TMSTS_TMTSTS_1))
   {
      return 0;
   }
   else
   {
      return 1;
   }
}

/***********************************************************************************************************************
* Function Name: R_CAN0_Send
* Description  : This function sends CAN0 data.
* Arguments    : id_hi, id_lo -
*                    CAN packet ID
*                length -
*                    transimt data size
*                tx_buf -
*                    transmit data pointer
* Return Value : none
***********************************************************************************************************************/
void R_CAN0_Send(uint16_t id_hi, uint16_t id_lo, uint8_t length, uint8_t * tx_buf)
{
   uint8_t index, buffer_num;

   // find avaliable buffer
   for(buffer_num = 0; buffer_num < 4; buffer_num++)
   {
      if(1 == R_CAN0_Is_Transmitted(buffer_num))
      {
         break;
      }
   }

   if(buffer_num > 4)
   {
      return;
   }

   // fill register
   *(&TMIDH0 + buffer_num * 0x08) = id_hi;                        //*0x10 for byte, *0x08 for word
   *(&TMIDL0 + buffer_num * 0x08) = id_lo;                        //*0x10 for byte, *0x08 for word

   *(&TMPTR0 + buffer_num * 0x08) = ((uint16_t)length) << 12;     //*0x10 for byte, *0x08 for word

   for(index = 0; index < length; index++)
   {
      *(&TMDF00L + buffer_num * 0x10 + index) = *(tx_buf + index);
   }

   *(&TMSTS0 + buffer_num) = _0000_CAN_TMSTS_TMTRF_0;

   *(&TMC0 + buffer_num) = _00_CAN_TMC_TMOM_0 | _00_CAN_TMC_TMTAR_0 | _01_CAN_TMC_TMTR_1;
}

/***********************************************************************************************************************
* Function Name: R_CAN_Set_Rx_Buffer
* Description  : This function set ID of CAN0 receive buffer.
* Arguments    : buffer_num -
*                    CAN receive buffer number
*                id_hi, id_lo -
*                    CAN packet ID
*                mask_hi, mask_lo -
*                    ID filter
* Return Value : none
***********************************************************************************************************************/
void R_CAN0_Set_Rx_Buffer(uint8_t buffer_num, uint16_t id_hi, uint16_t id_lo, uint16_t mask_hi, uint16_t mask_lo)
{
   //global reset mode
   GCTRL = _0000_CAN_GCTRL_THLEIE_0 | _0000_CAN_GCTRL_MEIE_0 | _0000_CAN_GCTRL_DEIE_0 | _0000_CAN_GCTRL_GSLPR_0 | _0001_CAN_GCTRL_GMDC_1;

   while(GSTS != _01_CAN_GSTS_GRSTSTS_1);

   GRWCR = _0000_CAN_GRWCR_RPAGE_0;
   *(&GAFLIDL0 + buffer_num * 0x06) = id_lo;
   *(&GAFLIDH0 + buffer_num * 0x06) = id_hi;
   *(&GAFLML0 + buffer_num * 0x06) = mask_lo;
   *(&GAFLMH0 + buffer_num * 0x06) = mask_hi;
   *(&GAFLPL0 + buffer_num * 0x06) = _8000_CAN_GAFLPL_GAFLRMV_1 | ((uint16_t)buffer_num << 8) | _0000_CAN_GAFLPL_GAFLFDP4_0 |
                                     _0000_CAN_GAFLPL_GAFLFDP1_0 | _0000_CAN_GAFLPL_GAFLFDP0_0;
   *(&GAFLPH0 + buffer_num * 0x06) = _0000_CAN_GAFLPH_GAFLDLC_0;
   GRWCR = _0001_CAN_GRWCR_RPAGE_1;

   //global operating mode
   GCTRL = _0000_CAN_GCTRL_THLEIE_0 | _0000_CAN_GCTRL_MEIE_0 | _0000_CAN_GCTRL_DEIE_0 | _0000_CAN_GCTRL_GSLPR_0 | _0000_CAN_GCTRL_GMDC_0;

   while(GSTS & (_08_CAN_GSTS_GRAMINIT_1 | _04_CAN_GSTS_GSLPSTS_1 | _02_CAN_GSTS_GHLTSTS_1 | _01_CAN_GSTS_GRSTSTS_1));

   //channel communication mode
   C0CTRL = _0000_CAN_C0CTRL_ALIE_0 | _0000_CAN_C0CTRL_BLIE_0 | _0000_CAN_C0CTRL_OLIE_0 | _0000_CAN_C0CTRL_BORIE_0 | _0000_CAN_C0CTRL_BOEIE_0 |
            _0000_CAN_C0CTRL_EPIE_0 | _0000_CAN_C0CTRL_EWIE_0 | _0000_CAN_C0CTRL_BEIE_0 | _0000_CAN_C0CTRL_CSLPR_0 | _0000_CAN_C0CTRL_CHMDC_0;

   while(C0STSL != _0080_CAN_C0STSL_COMSTS_1);
}

/***********************************************************************************************************************
* Function Name: R_CAN_Set_Baudrate
* Description  : This function set baud rate of CAN0.
* Arguments    : baud_rate -
*                    baud rate, unit is 1kbps, max 1000kbps
* Return Value : none
***********************************************************************************************************************/
void R_CAN0_Set_Baudrate(uint16_t baud_rate)
{
   //channel reset mode
   C0CTRL = _0000_CAN_C0CTRL_ALIE_0 | _0000_CAN_C0CTRL_BLIE_0 | _0000_CAN_C0CTRL_OLIE_0 | _0000_CAN_C0CTRL_BORIE_0 | _0000_CAN_C0CTRL_BOEIE_0 |
            _0000_CAN_C0CTRL_EPIE_0 | _0000_CAN_C0CTRL_EWIE_0 | _0000_CAN_C0CTRL_BEIE_0 | _0000_CAN_C0CTRL_CSLPR_0 | _0001_CAN_C0CTRL_CHMDC_1;

   while(C0STSL != _0001_CAN_C0STSL_CRSTSTS_1);

   //set clock      fcan=16MHz, 16Tq,
   GCFGL = _0000_CAN_GCFGL_TSSS_0 | _0000_CAN_GCFGL_TSP_0 | _0000_CAN_GCFGL_DCS_0 | _0000_CAN_GCFGL_MME_0 | _0000_CAN_GCFGL_DRE_0 |
           _0000_CAN_GCFGL_DCE_0 | _0000_CAN_GCFGL_TPRI_0;
   C0CFGH = _0000_CAN_C0CFGH_SJW_0 | _0030_CAN_C0CFGH_TSEG2_3 | _000A_CAN_C0CFGH_TSEG1_10;  // 1+4+11=16Tq
   C0CFGL = 1000 / baud_rate - 1;

   //channel communication mode
   C0CTRL = _0000_CAN_C0CTRL_ALIE_0 | _0000_CAN_C0CTRL_BLIE_0 | _0000_CAN_C0CTRL_OLIE_0 | _0000_CAN_C0CTRL_BORIE_0 | _0000_CAN_C0CTRL_BOEIE_0 |
            _0000_CAN_C0CTRL_EPIE_0 | _0000_CAN_C0CTRL_EWIE_0 | _0000_CAN_C0CTRL_BEIE_0 | _0000_CAN_C0CTRL_CSLPR_0 | _0000_CAN_C0CTRL_CHMDC_0;

   while(C0STSL != _0080_CAN_C0STSL_COMSTS_1);
}
